#!/usr/bin/python2.5
class Table:

    def __init__(self, num_lines, num_rows):
        self.board = []
        for l in range(num_lines):
            line = []
            for r in range(num_rows):
                line.append(Ground())
            self.board.append(line)
    
    def __str__(self):
        visible_board = []
        for line in xrange(len(self.board)):
            visible_board.append([])
            for piece in self.board[line]:
                visible_board[line].append(piece.get_name())
        return str(visible_board)
    
    def get(self, line, row):
        return self.board[line][row]
    
    def put(self, element, line, row):
        self.board[line][row] = element
               
    def remove(self, line, row):
        element = self.get(line, row)
        self.clear(line, row)
        return element
    
    def is_clean(self, line, row):
        return isinstance(self.get(line, row), Ground) 
    
    def clear(self, line, row):
        self.put(Ground(), line, row)

class Ground:
    
    def __init__(self):
        self.name = 'Ground'
        
    def get_name(self):
        return self.name          

    def __str__(self):
        return self.name
                
class Water:
    
    def __init__(self):
        self.name = 'Water'

    def get_name(self):
        return self.name

    def __str__(self):
        return self.name


class Piece:

    def __init__(self,name,owner):
        self.name = name
        self.owner = owner

    def get_owner(self):
        return self.owner

    def get_name(self):
        return self.name

    def __str__(self):
        return self.name
    
class MobilePiece(Piece):
    
    # TODO: All piece have to know where it is. Maybe, we could create one class to each piece  
    def __init__(self, name, value, owner):
            Piece.__init__(self, name, owner)
            self.value = value

    def __cmp__(self, other_piece):
        if isinstance(other_piece , MobilePiece):
            return cmp(self.get_value(), other_piece.get_value())
        return 1

    def get_value(self):
        return self.value

class ImmovablePiece(Piece):
    # TODO: Maybe we could create a class flag and other bomb 
    def __init__(self, name, owner):
        Piece.__init__(self, name, owner)
       

class Army:
 
    def __init__(self,owner):
        self.owner = owner
        self.name = 'Allied Army'
        self.pieces = {}
        self.length = 0
        mobile_pieces =  [('marshal', 1, 10), ('general', 1, 9), ('colonel', 2, 8), 
                      ('major', 3, 7), ('captain', 4, 6), ('lieutenant', 4, 5), 
                      ('sergeant', 4, 4), ('miner', 5, 3), ('scout', 8, 2), ('spy', 1, 1)]
        immovable_pieces = [('bomb', 6), ('flag', 1)]
        
        
        for name, quant, value in mobile_pieces:
            for piece in xrange(quant):
                self.add_piece(MobilePiece(name, value, owner))
            
        for name, quant in immovable_pieces:
            for piece in xrange(quant):
                self.add_piece(ImmovablePiece(name, owner))
    
    def get_owner(self):
        return self.owner
    
    def get_name(self):
        return self.name
    
    def add_piece(self,piece):
        list = self.pieces.get(piece.get_name(),[])
        list.append(piece)
        self.pieces[piece.get_name()] = list
        self.length += 1

    def get_piece(self, name):
        return self.pieces.get(name,[])[0]
    
    def remove_piece(self, name):
        list = self.pieces.get(name,[])
        if len(list) > 0:
            self.length -= 1
            return list.pop()

    def count(self, name):
        return len(self.pieces.get(name,[]))

    def __len__(self):
        return self.length
    
    def __str__(self):
        result = '('
        for name,list in sorted(self.pieces.items()):
            result += '%s: %s ' % (name,len(list))
        result += ')'
        return result
    
class ShadowArmy:
    
    def __init__(self, owner = 'Enemy'):
        self.owner = owner
        self.name = 'Shadow Army' 
        self.shadow_army = []
        for piece in xrange(40):
            shadow = MobilePiece('Shadow', None, 'Enemy')
            self.shadow_army.append(shadow)        
        
    def __str__(self):
        return self.name
    
    def get_name(self):
        return self.name
    
    def get_owner(self):
        return self.owner
    
class CombatListener:

    def piece_added(self, piece, line, row):
        pass
    
    def __str__(self):
        return self.name
        
class TextCombatListener(CombatListener):

    def piece_added(self, piece, line, row):
        print 'Piece added: %s (%s,%s)' % (piece, line, row)

    def __str__(self):
        return self.name


class CombatGame:
    
    """ The game's logic"""
    
    backward_count = 0
    POPULATING = 0
    BATTLE = 1
    ATTACK = 2
    END = 3

    valid_status = [POPULATING, BATTLE, ATTACK, END]  

    def __init__(self):
        self.status = CombatGame.POPULATING
        self.army = Army('Allied')
        self.listeners = []
        self.add_listener(TextCombatListener())
        self.allied_graveyard = []
        self.enemy_graveyard = []
        self.table = Table(10, 10) 
        # Populating with water
        lake = Water()
        for pos in range(2,8):
            if pos in [2, 3, 6, 7]:
                self.table.put(lake, 4, pos)
                self.table.put(lake, 5, pos)    
    
    def __str__(self):
        return str(self.table)
    
    def change_status(self, status):
        if status in CombatGame.valid_status and status != CombatGame.POPULATING:
            if self.status == CombatGame.POPULATING and status == CombatGame.BATTLE:
                self.populate_with_shadows()
            self.status = status

    def add_piece(self, name, line, row):
        if self.status == CombatGame.POPULATING:
            if line < 4 and self.table.is_clean(line, row) and self.army.count(name) > 0:
                piece = self.army.remove_piece(name)
                self.table.put(piece, line, row)
            else:
                raise Exception("That's a Wrong Add")

    def change_pieces(self, line1, row1, line2, row2):
        if self.status == CombatGame.POPULATING:
            if line2 < 4:
                piece1 = self.table.remove(line1, row1)
                piece2 = self.table.remove(line2, row2)
                self.table.put(piece2, line1, row1)
                self.table.put(piece1, line2, row2)
            else:
                raise Exception("That's a Wrong Place")

    def populate_with_shadows(self):
        self.shadows = ShadowArmy('Enemy')
        for line in range(4):
            for row in range(10):                
                self.table.put(self.shadows.shadow_army.pop(0), 9 - line, 9 - row)

    def change_shadow(self, line, row, real_piece):
        # FIXME: test me... While we have the attack we cannot discard the shadow, if it wins, it will continue playing
        self.table.remove(line, row)
        self.table.put(real_piece, line, row)
            
    #def real_piece(self, piece):
    #    return piece        

    def show_pieces(self, line1, row1, line2, row2): ## We have to use Pygame HERE!!!!!!
        print self.table.get(line1, row1)
        print self.table.get(line2, row2)
                
    def is_my_turn(self, bool = True):
         return bool

    def begining_turn(self):
        print "It's Your turn"    

      
    def move(self, line1, row1, line2, row2):
        self.is_my_turn()
        if self.status == CombatGame.BATTLE:
            piece = self.table.get(line1, row1)
            if isinstance(piece, MobilePiece) and (line2, row2) in self.where_move(line1,row1):
                if line2 == line1-1:
                    if CombatGame.backward_count >= 3:
                        return
                    else:
                        CombatGame.backward_count += 1
                self.table.remove(line1, row1)
                self.table.put(piece, line2, row2)
                self.is_my_turn(False)
                
    def where_move(self, line, row):
        piece = self.table.get(line,row)
        if self.status == CombatGame.BATTLE and isinstance(piece, MobilePiece):
            possible_moves = []
            for direction, orientation in [(line, '+'), (line, '-')]:
                for cord in self.move_incrementer(direction, orientation, piece):
                    if self.table.is_clean(cord, row):
                        possible_moves.append((cord, row))
                    else:
                        break
            for direction, orientation in [(row, '+'), (row, '-')]:
                for cord in self.move_incrementer(direction, orientation, piece):
                    if self.table.is_clean(line, cord):
                        possible_moves.append((line, cord))
                    else:
                        break
            return possible_moves  
    
    def move_incrementer(self, direction, orientation, piece):
        moves = []
        if piece.get_name() == 'Scout':
            if orientation == '+':
                while direction < 9:
                    direction+= 1
                    moves.append(direction)
            elif orientation == '-':
                while direction > 0:
                    direction-= 1
                    moves.append(direction)
        else:
            if orientation == '+' and direction + 1 < 9:
                    moves.append(direction + 1)
            elif orientation == '-' and direction - 1 >= 0:
                moves.append(direction - 1)                          
        return moves
    
    
    def attack_to(self, line1, row1, line2, row2, real_piece): # I did a temporary change to test the methods, they are OK!!!! If you want to test, the code is yours =D
        self.is_my_turn()
        piece1, piece2 = self.table.get(line1, row1), self.table.get(line2, row2)
        if self.status == CombatGame.ATTACK:
            # We have to find the shadow and change it!!!
            shadow = piece2 
            self.change_shadow(line2, row2, real_piece)
            self.show_pieces(line1, row1, line2, row2)
            loser = self.whos_the_loser(line1, row1, line2, row2)
            #if loser == [(line1, row1)]:                            
            #    self.change_shadow(line2, row2, shadow)            # We don't need!?
                                        
            for piece in loser:
                if piece == (line1, row1):
                    self.add_to_graveyard(line1, row1, self.allied_graveyard)
                if piece == (line2, row2):
                    self.add_to_graveyard(line2, row2, self.enemy_graveyard)
            
            if loser == [(line2, row2)]:
                self.change_status(1)
                self.move(line1, row1, line2, row2)
            self.change_status(1)
            self.is_my_turn(False)

        else:
            raise Exception('Wrong attack movement')    
        
       
    def whos_the_loser(self, line1, row1, line2, row2):
        ''' It search what is the case of attack and return the loser''' 
        
        if (line2, row2) in self.where_attack(line1, row1):
                piece1 = self.table.get(line1, row1)
                piece2 = self.table.get(line2, row2)
                if isinstance(piece2, MobilePiece):
                    if piece1.get_name() == 'Spy' and piece2.get_name() == 'Marshal':
                        loser = [(line2, row2)]
                    elif piece1 > piece2:
                        loser = [(line2, row2)]
                    elif piece1 < piece2:
                        loser = [(line1, row1)]
                    else:
                        loser = [(line1, row1), (line2, row2)]
                elif isinstance(piece2, ImmovablePiece):
                    if piece1.get_name() == 'Miner' and piece2.get_name() == 'Bomb':
                        loser = [(line2, row2)]
                    elif piece2.get_name() == 'Bomb':
                        loser = [(line1, row1), (line2, row2)]
                    elif piece2.get_name() == 'Flag':
                        self.change_status(3)
                return loser                
        
    def where_attack(self, line, row):
        if isinstance(self.table.get(line, row), MobilePiece):
            attacks = []
            up, down, left, right = (line + 1, row), (line - 1, row), (line, row - 1), (line, row + 1)
            possible_attacks = [up, down, left, right]
            on_board = xrange(10) # This it is only a simulation of board
            for attack in possible_attacks:
                if attack[0] in on_board and attack[1] in on_board:
                    piece = self.table.get(attack[0], attack[1])
                    if isinstance(piece, Piece) and  piece.get_owner() != self.table.get(line, row).get_owner():
                        attacks.append(attack)
            return attacks
        
                
    def show_graveyard(self):
        return self.allied_graveyard, self.enemy_graveyard
        
    def add_to_graveyard(self, line, row, graveyard):
        graveyard.append(self.table.get(line, row))
        self.table.remove(line, row)
        
    def add_listener(self, listener):
        self.listeners.append(listener)
    
    def attack_button(self, line, row):
        if len(self.where_attack(line, row)) > 0:
            return True # This method will call an interface method, to unlock or not the attack button
            
    def battle_button(self):
        if len(self.army) == 0:
            self.change_status(BATTLE)
    
    #@todo: We have to create a method to END the game
